package com.generic.mybatis.dal.interceptor.automap;

import com.generic.mybatis.dal.dao.annotation.Join;
import org.apache.ibatis.jdbc.SQL;
import org.apache.ibatis.mapping.ResultMapping;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

/**
 * 联合查询 left join 、right join
 *
 * @author wuaj
 */
public class JoinInfo {

    private final Field field;

    private final Join joinInfo;

    private final TableMapper tableMapper;

    private final TableMapper joinTableMapper;

    public JoinInfo(TableMapper tableMapper, Field field, Join joinInfo) {
        this.tableMapper = tableMapper;
        this.field = field;
        this.joinInfo = joinInfo;
        joinTableMapper = TableMapperHolder.getTableMapper(getJoinClass());
        if (joinTableMapper == null) {
            throw new RuntimeException(String.format("can't find mapper for class %s", getJoinClass().getName()));
        }
    }

    public TableMapper getJoinTableMapper() {
        return joinTableMapper;
    }

    public Class getJoinClass() {
        return field.getType();
    }

    public String getJoinTable() {
        return joinTableMapper.getTableName();
    }

    public String getJoinAlias() {
        return field.getName();
    }

    public String getJoinField() {
        return joinInfo.joinField();
    }

    public String[] getIncludeFields() {
        return joinInfo.includeFields();
    }

    public Field getField() {
        return field;
    }

    public Join.JoinType getJoinType() {
        return joinInfo.type();
    }

    public SQL buildJoinStatement(SQL sql) {
        String template = "%s %s on %s.%s = %s.%s";
        FieldMapper fm = tableMapper.getFieldMapperCache().get(joinInfo.field());
        String masterField = joinInfo.field();
        if (fm != null) {
            masterField = fm.getDbFieldName();
        }
        String statement = String.format(template, getJoinTable(), getJoinAlias(),
                tableMapper.getAlias(), masterField, getJoinAlias(), joinInfo.joinField());
        switch (getJoinType()) {
            case Inner:
                sql.INNER_JOIN(statement);
                break;
            case Left:
                sql.LEFT_OUTER_JOIN(statement);
                break;
            case Right:
                sql.RIGHT_OUTER_JOIN(statement);
                break;

        }
        return sql;
    }

    public SQL buildSelectStatement(SQL sql) {
        for (FieldMapper fieldMapper : joinTableMapper.getFieldMapperCache().values()) {
            sql.SELECT(String.format("%s.%s as %s__%s", getJoinAlias(),
                    fieldMapper.getDbFieldName(), getJoinAlias(), fieldMapper.getFieldName()));
        }
        return sql;
    }

    public List<ResultMapping> buildResultMappings() {
        List<ResultMapping> mappings = new ArrayList<ResultMapping>();
        for (FieldMapper fieldMapper : joinTableMapper.getFieldMapperCache().values()) {
            ResultMapping.Builder builder = new ResultMapping.Builder(tableMapper.getConfiguration(),
                    String.format("%s.%s", getJoinAlias(), fieldMapper.getFieldName()),
                    String.format("%s__%s", getJoinAlias(), fieldMapper.getFieldName()), fieldMapper.getField().getType());
            mappings.add(builder.build());
        }
        return mappings;
    }
}
